#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <fstream>
#include <sstream>

#include "Socket.hpp"
#include "TcpServer.hpp"
#include "Log.hpp"

using namespace socket_ns;

static const std::string sep = "\r\n";
static const std::string httpversion = "HTTP/1.0";
static const std::string space = " ";
static const std::string wwwroot = "wwwroot";
static const std::string homepage = "index.html";
static const std::string header_sep = ": ";
static const std::string filesuffixsep = ".";
static const std::string args_sep = "?";

class HttpResponse;
class HttpRequest;
using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;

class HttpRequest // 请求收到后要做反序列化转化成结构化数据处理
{
private:
	std::string GetOneLine(std::string &request)
	{
		if (request.empty())
			return request;
		// 一行最后都是\r\n
		auto pos = request.find(sep);
		if (pos == std::string::npos)
			return std::string();

		std::string retstr = request.substr(0, pos);
		request.erase(0, pos + sep.size());
		return retstr.empty() ? sep : retstr; // 报头最后一行是空行
	}

	bool ParseHeaderHelp(const std::string &header, std::string *k, std::string *v)
	{
		auto pos = header.find(header_sep);
		if (pos == std::string::npos)
		{
			return false;
		}

		*k = header.substr(0, pos);
		*v = header.substr(pos + header_sep.size());
		return true;
	}

	bool ParseReqLine()		//分析首报
	{
		if (_req_fline.empty())
		{
			return false;
		}
		std::stringstream ss(_req_fline);
		ss >> _method >> _url >> _version;

		// /index.html?use=zhangsan&passwd=123456
		if (strcasecmp("get", _method.c_str()) == 0) // 如果是get方式，就要再url里找有没有提交的信息
		{
			auto pos = _url.find(args_sep);
			if (pos != std::string::npos)
			{
				LOG(INFO, "change begin, url: %s\n", _url.c_str());
				_args = _url.substr(pos + args_sep.size());
				_url.resize(pos);
				LOG(INFO, "change done, url: %s, _args: %s\n", _url.c_str(), _args.c_str());
			}
		}

		_path += _url;

		// 判断一下是不是请求的/ -- wwwroot/
		if (_path[_path.size() - 1] == '/')
		{
			_path += homepage;
		}

		auto pos = _path.rfind(filesuffixsep);
		if (pos == std::string::npos)
			_suffix = ".unknown";
		else
			_suffix = _path.substr(pos);

		LOG(INFO, "client wang get path: %s,suffix: %s\n", _path.c_str(), _suffix.c_str());
		return true;
	}

	bool ParseHeader()
	{
		// 分成逐行进行parse
		for (auto &header : _req_header)
		{
			std::string k, v;
			if (ParseHeaderHelp(header, &k, &v))
			{
				_headers.insert(std::make_pair(k, v));
			}
		}

		return true;
	}

public:
	HttpRequest() : _blank_line(sep), _path(wwwroot)
	{
	}
	~HttpRequest() {}

	// 一个报文有很多行，通过每次取一行处理转化
	void Derialize(std::string &request)
	{
		_req_fline = GetOneLine(request);
		while (true)
		{
			std::string line = GetOneLine(request);
			if (line.empty())
				break;
			else if (line == sep)
			{
				_req_text = request;
			}
			else
			{
				_req_header.emplace_back(line);
			}
		}

		ParseReqLine();
		ParseHeader();
	}

	void Print()
	{
		std::cout << "====" << _req_fline << std::endl;
		for (auto &header : _req_header)
		{
			std::cout << "****" << header << std::endl;
		}
		std::cout << _blank_line;
		std::cout << _req_text << std::endl;

		std::cout << "method ### " << _method << std::endl;
		std::cout << "url ### " << _url << std::endl;
		std::cout << "path ### " << _path << std::endl;
		std::cout << "httpverion ### " << _version << std::endl;
		for (auto &header : _headers)
		{
			std::cout << "@@@" << header.first << " - " << header.second << std::endl;
		}
	}

	bool IsExec()
	{
		return !_args.empty() || !_req_text.empty();
	}

	std::string Args()
	{
		return _args;
	}

	std::string Text()
	{
		return _req_text;
	}

	std::string Path()
	{
		return _path;
	}

	std::string Suffix()
	{
		return _suffix;
	}

	std::string Method()
	{
		return _method;
	}

private:
	// 原始协议内容
	std::string _req_fline;				  // 首行: [方法] + [url] + [版本]
	std::vector<std::string> _req_header; // Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
	std::string _blank_line;			  // 空行
	std::string _req_text;				  // 正文

	// 期望解析的结果
	std::string _method; // 方法
	std::string _url;
	std::string _args;	  // 选项
	std::string _path;	  // 文件路径
	std::string _suffix;  // 文件后缀
	std::string _version; // 版本

	std::unordered_map<std::string, std::string> _headers;
};

class HttpResponse
{
public:
	HttpResponse() : _blank_line(sep), _version(httpversion)
	{
	}
	void AddStatusLine(int code, std::string desc)
	{
		_code = code;
		_desc = desc; // TODO
	}
	void AddHeader(const std::string &k, const std::string &v)
	{
		_headers[k] = v; // 有就替换。没有就添加
	}

	void AddHeader(const std::string &cookiestr)
	{
		_resp_header.emplace_back(cookiestr);
	}

	void AddText(const std::string &text)
	{
		_resp_text = text;
	}

	std::string Serialize()
	{
		_status_line = _version + space + std::to_string(_code) + space + _desc + sep;
		for (auto &header : _headers)
		{
			_resp_header.emplace_back(header.first + header_sep + header.second + sep);
		}

		// 序列化
		std::string respstr = _status_line;
		for (auto &header : _resp_header)
		{
			respstr += header;
		}
		respstr += _blank_line;
		respstr += _resp_text;
		return respstr;
	}

	void print()
	{
		std::cout << _version << _code << _desc << std::endl;
		for (auto &h : _headers)
		{
			std::cout << h.first << ":" << h.second << std::endl;
		}
		std::cout << _blank_line << ::std::endl;

		// std::cout<<_resp_text<<::std::endl;
	}
	~HttpResponse() {}

private:
	// 构建应答的必要字段
	std::string _version;								   // 版本号
	int _code;											   // 状态码
	std::string _desc;									   // 状态码解释
	std::unordered_map<std::string, std::string> _headers; // 报头

	// 应答的结构化字段
	std::string _status_line;			   // 首行: 版本+状态码+状态
	std::vector<std::string> _resp_header; // Header: 请求的属性
	std::string _blank_line;			   // 空行
	std::string _resp_text;				   // 正文
};

class Factory
{
public:
	static std::shared_ptr<HttpRequest> BuildHttpRequest()
	{
		return std::make_shared<HttpRequest>();
	}
	static std::shared_ptr<HttpResponse> BuildHttpResponse()
	{
		return std::make_shared<HttpResponse>();
	}
};

#define TEST
// #define TEST_1
// #define TEST_2
#define TEST_3


class HttpServer
{
private:
	static std::string GetMonthName(int month)
    {
        std::vector<std::string> months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
        return months[month];
    }
    static std::string GetWeekDayName(int day)
    {
        std::vector<std::string> weekdays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
        return weekdays[day];
    }
    static std::string ExpireTimeUseRfc1123(int t) // 秒级别的未来UTC时间
    {
        time_t timeout = time(nullptr) + t;
        struct tm *tm = gmtime(&timeout); // 这里不能用localtime，因为localtime是默认带了时区的. gmtime获取的就是UTC统一时间
        char timebuffer[1024];
        //时间格式如: expires=Thu, 18 Dec 2024 12:00:00 UTC
        snprintf(timebuffer, sizeof(timebuffer), "%s, %02d %s %d %02d:%02d:%02d UTC", 
            GetWeekDayName(tm->tm_wday).c_str(),
            tm->tm_mday,
            GetMonthName(tm->tm_mon).c_str(),
            tm->tm_year+1900,
            tm->tm_hour,
            tm->tm_min,
            tm->tm_sec
        );
        return timebuffer;
    }
public:
	HttpServer()
	{
		_mime_type.insert(std::make_pair(".html", "text/html"));
		_mime_type.insert(std::make_pair(".css", "text/css"));
		_mime_type.insert(std::make_pair(".js", "application/x-javascript"));
		_mime_type.insert(std::make_pair(".png", "image/png"));
		_mime_type.insert(std::make_pair(".jpg", "image/jpeg"));
		_mime_type.insert(std::make_pair(".unknown", "text/html"));

		_code_to_desc.insert(std::make_pair(100, "Continue"));
		_code_to_desc.insert(std::make_pair(200, "OK"));
		_code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
		_code_to_desc.insert(std::make_pair(302, "Found"));
		_code_to_desc.insert(std::make_pair(404, "Not Found"));
		_code_to_desc.insert(std::make_pair(500, "Internal Server Error"));
	}

	static std::string ProveCookieWrite() // 证明cookie能被写入浏览器
    {
        return "Set-Cookie: username=zhangsan;";
    }
    static std::string ProveCookieTimeOut()
    {
        return "Set-Cookie: username=zhangsan; expires=" + ExpireTimeUseRfc1123(60) + ";"; // 让cookie 1min后过期
    }
    static std::string ProvePath()
    {
        return "Set-Cookie: username=zhangsan; path=/a/b;";
    }
    static std::string ProveOtherCookie()
    {
        return "Set-Cookie: passwd=1234567890; path=/a/b;";
    }

	void AddHandler(const std::string functionname, func_t fun)
	{
		std::string key = wwwroot  + functionname;
		_funcs[key] = fun;
	}


	std::string ReadFileContent(const std::string &path, int *size) // size是输出读到多少
	{
		// 要按照二进制打开
		std::ifstream in(path, std::ios::binary);
		if (!in.is_open())
		{
			// LOG(DEBUG,"open error,path:%s",path.c_str());
			return std::string();
		}

		// get length of file:
		in.seekg(0, in.end);
		int filesize = in.tellg();
		in.seekg(0, in.beg);

		std::string content;
		content.resize(filesize);
		in.read((char *)content.c_str(), filesize);
		in.close();
		*size = filesize;
		return content;
	}
	std::string HandlerHttpReqeust(std::string req) // req是传入的报文
	{
#ifdef TEST
	#ifdef TEST_1
		std::cout << "---------------------------------------" << std::endl;
		std::cout << req;

		std::string response = "HTTP/1.0 200 OK\r\n"; // 404 NOT Found
		response += "\r\n";
		response += "<html><body><h1>hello xdt, hello bite!</h1></body></html>";

		return response;	
	#endif
	#ifdef TEST_2
		std::cout << req << std::endl;
		auto request = Factory::BuildHttpRequest();
		request->Derialize(req);

		auto response = Factory::BuildHttpResponse();

		int code = 0;
		std::string newurl = "http://www.qq.com";
		std::string suffix = request->Suffix();

		if (request->Path() == "wwwroot/redir") // 测试重定向和验证location
		{
			code = 301;
			response->AddStatusLine(code, _code_to_desc[code]);
			response->AddHeader("Location", newurl);
		}
		else
		{
			int contentsize = 0;
			std::string text = ReadFileContent(request->Path(), &contentsize);
			if (text.empty())
			{
				code = 404;
				response->AddStatusLine(code, _code_to_desc[code]);
				std::string text404 = ReadFileContent("wwwroot/404.html", &contentsize);
				response->AddHeader("Content-Length", std::to_string(contentsize));
				response->AddHeader("Content-Type", _mime_type[suffix]);
				response->AddText(text404);
			}
			else
			{
				std::string suffix = request->Suffix();
				response->AddStatusLine(code, _code_to_desc[code]);
				response->AddHeader("Content-Length", std::to_string(contentsize));
				response->AddText(text);
				response->AddHeader("Content-Type", _mime_type[suffix]);
			}
		}

		return response->Serialize();
	#endif
	#ifdef TEST_3
		std::cout << "---------------------------------------" << std::endl;
        std::cout << req<<std::endl;
		auto request = Factory::BuildHttpRequest();
		request->Derialize(req);

		if(request->IsExec())		//如果是别的访问方法，调出去单独处理，在main中传入
		{
			auto response = _funcs[request->Path()](request);
			return response->Serialize();
		}
		else
        {
            auto response = Factory::BuildHttpResponse();
            int code = 200;
            int contentsize = 0;
            std::string text = ReadFileContent(request->Path(), &contentsize);
            if (text.empty())		
            {
                code = 404;
                response->AddStatusLine(code, _code_to_desc[code]);
                std::string text404 = ReadFileContent("wwwroot/404.html", &contentsize);
                response->AddHeader("Content-Length", std::to_string(contentsize));
                response->AddHeader("Content-Type", _mime_type[".html"]);
                response->AddText(text404);
            }
            else
            {
                std::string suffix = request->Suffix();
                response->AddStatusLine(code, _code_to_desc[code]);
                response->AddHeader("Content-Length", std::to_string(contentsize));
                response->AddText(text);
                response->AddHeader("Content-Type", _mime_type[suffix]);
            }
            return response->Serialize();
        }

	#endif
#endif
	}
	~HttpServer() {}

private:
	std::unordered_map<std::string, std::string> _mime_type; // 文件类型
	std::unordered_map<int, std::string> _code_to_desc;		 // 状态码描述
	std::unordered_map<std::string, func_t> _funcs;			 // 不同请求。不同处理
};